package 创建型模式

import java.io.ObjectStreamException

/**
 * 保证一个类仅有一个实例，并提供一个访问它的全局访问点
 */

/**
 * 饿汉模式(类加载时完成初始化)
 * 类加载较慢，但获取对象的速度快
 * 避免了多线程的同步问题
 * 如果从始至终未使用过这个实例，则会造成内存的浪费
 */
class Singleton private constructor() {
    companion object {
        private val INSTANCE = Singleton()
        fun getInstance() = INSTANCE
    }
}

/**
 * 懒汉式(线程不安全)
 * 声明静态对象，并在调用时初始化
 * 在第一次加载时需要实例化，反应慢些，且在多线程时不能正常工作
 */
class Singleton2 private constructor() {
    companion object {
        private var INSTANCE: Singleton2? = null
        fun getInstance(): Singleton2? {
            if (INSTANCE == null) {
                INSTANCE = Singleton2()
            }
            return INSTANCE
        }
    }
}

/**
 * 懒汉式(线程安全)
 * 每次调用时进行同步，会造成不必要的开销
 */
class Singleton3 private constructor() {
    companion object {
        private var INSTANCE: Singleton3? = null
        fun getInstance(): Singleton3? {
            synchronized(Singleton3::class.java) {
                if (INSTANCE == null) {
                    INSTANCE = Singleton3()
                }
                return INSTANCE
            }
        }
    }
}

/**
 * 双重检查DCL
 */
class Singleton4 private constructor() {
    companion object {
        @Volatile
        private var INSTANCE: Singleton4? = null
        fun getInstance(): Singleton4? {
            //减少不必要的同步
            if (INSTANCE == null) {
                synchronized(Singleton4::class.java) {
                    //volatile可见性，为null在创建
                    if (INSTANCE == null) {
                        INSTANCE = Singleton4()
                    }
                }
            }
            return INSTANCE
        }

    }
}

/**
 * 静态内部类
 * 只有在调用方法时才会初始化实例，不仅能够保证线程安全，也能够保证唯一实例
 */
class Singleton5 private constructor() {
    companion object {
        fun getInstance() = SingleHolder.instance

        class SingleHolder {
            companion object {
                val instance = Singleton5()
            }
        }
    }

    //反序列化
    @Throws(ObjectStreamException::class)
    fun readResolve(): Singleton5 {
        return getInstance()
    }
}

/**
 * 枚举类的每个枚举都是单例
 * 反序列化时会绕过普通类的private构造方法从而创建出多个实例
 * 提供readResolve方法一控制对象反序列化
 */

enum class Singleton6 {
    INSTANCE;

    fun doSomeThing() {

    }
}

fun main() {
    val singleton = Singleton4.getInstance()
}